package com.ysd.lis.util.qcrule;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.Data;
import org.apache.commons.lang3.NotImplementedException;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Data
public class Rule implements IRule{
        /// <summary>
        /// 类型
        /// </summary>
        public RuleType type;

        /// <summary>
        /// Id
        /// </summary>
        public String id ;
        /// <summary>
        /// 名称
        /// </summary>
        public String name ;

        /// <summary>
        /// A代表质控测定值个数
        /// </summary>
        public int a ;
        /// <summary>
        /// N代表质控测定值总个数
        /// </summary>
        public int n ;
        /// <summary>
        /// L是从正态统计量得到的质控界限
        /// </summary>
        public double l;




        public Rule(String id, String name, int a , int n, double l)
        {


            this.id = id;
            this.name = name;
            this.a = a;
            this.n= n;
            this.l = l;



            if (a > n)
            {
                throw new IllegalArgumentException("IQCRule A>N");
            }


            if (a <= 0)
            {
                throw new IllegalArgumentException("IQCRule A<=0");
            }

            if (l < 0)
            {
                throw new IllegalArgumentException("IQCRule L<0");
            }

        }


    @Override
    public RuleStatement Evaluate(QCResult result) {
        return RuleStatement.DISABLE;
    }


    @Override
    public  RuleStatement EvaluateMulti( List<QCResult> results)
    {

        //无数据,失败
        if (CollectionUtils.isEmpty(results))
        {
            return RuleStatement.FAILED;
        }
        //数据量必须大于1,13s,12s不适用于多质控物
        if (a <= 1)
        {
            return RuleStatement.FAILED;
        }


        QCResult result = ListToQCResult(results);

        if (null == result)
        {
            return RuleStatement.FAILED;
        }

        if (HasEmptyResult(result.getResults()))
        {
            return RuleStatement.DISABLE;
        }

        //置空已有失控规则
        //不能置空,需要保留其它规则的判断结果
        //result.Results.ForEach(p => { p.OutControlInfos = new List<OutControlInfo>(); p.IsOutControl = false; });


        if (Evaluate( result) == RuleStatement.OK)
        {

            //查找失控记录
            //Evaluate中失控点只会有一个
            //var oc = result.Results.Where(p => p.IsOutControl && p.OutControlInfos.Where(o => o.RuleId.Equals(Id)).Count() > 0).Last();
            List<Result> collect = result.getResults().stream().filter(p -> p.getIsOutControl() && p.getOutControlInfos().stream().filter(o -> o.getRuleId().equals(id)).count() > 0).collect(Collectors.toList());
            Result oc = collect.get(collect.size() - 1);
            //更改多质控物标志
            oc.getOutControlInfos()
                    .stream().filter(p ->p.getRuleId().equals(id))
                    .collect(Collectors.toList())
                    .forEach(o-> o.isMutiMaterial = true);

            //将失控标志等写入当天同次多质控物数据中，仅当关联时写入,否则不写入
            //待实现
            for (Result d : result.getResults().stream().filter(p -> p.getQCBatchNo().equals(oc.getQCBatchNo()) && !p.getId().equals(oc.getId())).collect(Collectors.toList()))
            {
                d.setIsOutControl(oc.getIsOutControl());
                d.getOutControlInfos().addAll(oc.getOutControlInfos().stream().filter(p->p.getRuleId().equals(id)).collect(Collectors.toList()));
                d.setOutControlInfos(d.getOutControlInfos().stream().distinct().collect(Collectors.toList()));
            }

            //将质控判断结果写入到原始结果中
            syncOutControlInfo(results, result);

            return RuleStatement.OK;
        }


        return RuleStatement.DISABLE;


    }
    protected  QCResult ListToQCResult(List<QCResult> results)
    {
        throw new NotImplementedException();
    }

    //protected virtual List<QCResult> ListToQCResult(List<QCResult> results)
    //{

    //    throw new NotImplementedException();
    //}

    /// <summary>
    /// 判断是否有为空的数据
    /// </summary>
    /// <param name="results"></param>
    /// <returns></returns>
    protected boolean HasEmptyResult(List<Result> results)
    {
        // return results.any(p =>string.isNumput(p.id) );

        return results.stream().filter(p->StringUtils.isBlank(p.getId())).findFirst().isPresent();
    }

    /// <summary>
    /// 多质控物判断时,将质控判断结果写入到原始结果中
    /// </summary>
    /// <param name="originalResults"></param>
    /// <param name="result"></param>
    protected void syncOutControlInfo( List<QCResult> originalResults, QCResult result)
    {

        List<Result> results = result.getResults().stream().filter(p -> p.getIsOutControl()).collect(Collectors.toList());
        for (Result r : results)
        {
            originalResults.forEach(re ->
            {
                // var or = p.Results.FirstOrDefault(p => p.Id.Equals(r.Id));
                Optional<Result> first = re.getResults().stream().filter(p -> p.getId().equals(r.getId())).findFirst();

                if (first.isPresent())
                {
                    Result or = first.get();
                    or.setIsOutControl(r.getIsOutControl());

                    or.getOutControlInfos().addAll(r.getOutControlInfos().stream().filter(p ->p.getIsMutiMaterial()&&!or.getOutControlInfos().contains(p)).collect(Collectors.toList()));
                }

            });


            //for (int i =0;i< originalResults.Count; i++)
            //{

            //    var or = originalResults[i].Results.FirstOrDefault(p => p.Id.Equals(r.Id));

            //    if (or != default)
            //    {
            //        or.IsOutControl = r.IsOutControl;

            //        var t = r.OutControlInfos.Where(p => p.IsMutiMaterial);

            //        List<OutControlInfo> outControlInfos = new();

            //        outControlInfos.AddRange(or.OutControlInfos);
            //        outControlInfos.AddRange(t);

            //        outControlInfos = outControlInfos.Distinct().ToList();

            //        or.OutControlInfos = outControlInfos;


            //    }
            //}


        }

    }
}
